# from my_dbg import *
import Node_trans_cfg as Node_trans_cfg
from List import List

"""
记录类型空间

解析类的定义，函数的定义， 类之间的依赖关系。

把

"""


class H_maker:
    def __init__(self, type_space, class_node):
        #self.tree = tree
        self.class_node = class_node
        self.type_space = type_space
    def class_code(self):
        return self.type_space.trans(self.class_node)
    def save(self, dir="inc"):
        f_name = dir+"/"+self.class_node.name+".h"
        with open(f_name, "w+") as f:
            OOvar(__name__, "save_H", f_name)
            f.write(self.class_code())


class Type_pair:
    def __init__(self, name, type_=None):
        self.type_ = type_
        self.name = name
    def __str__(self):
        return "<{type_}> {name}".format(type_=self.type_, name=self.name)


class Loop_stack:
    class Branch:
        def __init__(self): self.branch_stack=None; self.clear()
        def clear(self): 
            self.branch_stack = [[], ]
        def clear_cur_branch(self):
            self.branch_stack[-1] = []
        def push(self):  self.branch_stack.append([])
        def pop(self): self.branch_stack.pop()
        def add_src(self,src): self.branch_stack[-1].append(src)
        def pop_src(self): self.branch_stack[-1].pop()
        def branch_src_list(self): 
            r = self.branch_stack[-1]
            return r
        def loop_src_list(self):
            r = []
            for stack in self.branch_stack[::-1]:
                r += stack[::-1]
            return r

    def __init__(self): self.loop_stack=None; self.clear()
    def clear(self): 
        self.loop_stack = [Loop_stack.Branch(), ]
    def push_loop(self): 
        self.loop_stack.append(Loop_stack.Branch())
    def pop_loop(self): 
        self.loop_stack.pop()
    def func_src_list(self):
        r = []
        for body in self.loop_stack[::-1]:
            r += body.loop_src_list()
        return r
    
    def cur_branch_stack(self): return self.loop_stack[-1]
    def add_src(self, src): self.cur_branch_stack().add_src(src)
    def pop_src(self): self.cur_branch_stack().pop_src()
    def push_branch(self): self.cur_branch_stack().push()
    def pop_branch(self): self.cur_branch_stack().pop()
    def branch_src_list(self): return self.cur_branch_stack().branch_src_list()
    def loop_src_list(self): return self.cur_branch_stack().loop_src_list()
    
    @staticmethod
    def unit_test(): pass
    def clear_cur_branch(self):
        self.cur_branch_stack().clear_cur_branch()
    def return_raise_src_list(self):
        r = self.func_src_list()
        self.clear_cur_branch()
        return r
    def break_continue_src_list(self):
        r = self.loop_src_list()
        self.clear_cur_branch()
        return r
    def branch_in(self, branch_in_token="{{"): self.push_branch(); return branch_in_token
    def branch_out(self, branch_out_token="}}"): self.pop_branch(); return branch_out_token
    def loop_in(self, loop_in_token="{{"): self.push_loop(); return loop_in_token
    def loop_out(self, loop_out_token="}}"): self.pop_loop(); return loop_out_token
    def clear_func(self): self.clear()
# 1 假如没有 while/for:

#    return / raise:
#    抓取所有资源 + 清空本层.

#    {增加一层-------body_start
#       增加栈
#    }退出一层-------body_end
#       抓取本层 + 清空本层 + 弹出栈（本层）
#    在if的判断条件里面：
#    增加一个资源 === 在if的判断条件外面 增加一个资源。

#    把if 当作一个函数调用.

# 2 假如有while/for:
#    break, continue.
#    抓取while下的所有资源 + 清空本层.
   
#    return/raise
#    抓取所有资源 + 清空本层

# 3 if 超级调用：
#    相当于一个函数调用。 参数只有一个cond。
#    当cond里面存在成员函数调用：
#       使用预置变量.
#    while:
#    是 while 1: + if ()

# 4 body栈：
#    body_push.
#       stack_push.
#       stack_pop.
#    body_pop.

class Type_space:
    def __init__(self):
        #class, function_member, var_member
        self.class_space = {}
        #func_var, local var
        self.local_space = {}

        # record temporary var
        # each line
        # 临时变量 的产生。
        self.line_stack = [[], ]
        self.line_stack_after =  [[], ]
        # 临时变量 类型声明
        self.func_stack = []

        # 控制流
        # 自动资源
        #self.src_stack = []
        self.src = Loop_stack()
        self.cur_func_info = None

    def clear_local(self):
        self.local_space = {}
    def set_local(self, var_name, var_type):
        self.local_space[var_name] = var_type
    def get_local_type(self, var_name):
        if var_name in self.local_space:
            return self.local_space[var_name]
        else: 
            return None    
    
    def add_class(self, class_name):
        self.class_space[class_name] = {"var":[], "func":[]}
    def add_func(self, class_name, func):
        self.class_space[class_name]["func"].append(func)
    def add_member(self, class_name, member_name, member_type):
        self.class_space[class_name]["var"].append(Type_pair(member_name, member_type))
    def get_sub_member_type(self, class_name, member_name):
        Type = None
        if class_name not in self.class_space:
            OO_info("class_name [{class_name}] not in class_space  .member_name[{member_name}]".format(**locals()))
        for var in self.class_space[class_name]["var"]:
            if var.name == member_name:
                Type = var.type_
        return Type
    
    def func_type_str(self, func_node):
        return "func_type"
    
    def get_func(self, class_name, func_name):
        if class_name not in self.class_space:
            OO_info("class_name {class_name} not found!".format(**locals()))
            OO_info(self.class_space.keys())
            return None
        
        return List.find_e(self.class_space[class_name]["func"], lambda e: e.name == func_name)
        



    def add_tab(self, s):#缩进
        tab = " "*4
        s = s.splitlines()
        return tab+("\n"+tab).join(s)
    def trans(self, cur_node):
        r = eval("self._{}(cur_node)".format(cur_node.__class__.__name__))
        return r
    #def _method(self, node):

    def _ClassDef(self, node):
        # ClassDef(identifier name,
        #      expr* bases,
        #      keyword* keywords,
        #      stmt* body,
        #      expr* decorator_list)
        class_name = self.trans(node.name)
        self.add_class(class_name)
        base_list = []
        for base in node.bases:
            base_list.append(self.trans(base))
        base_list = "\nbase_list_gap\n".join(base_list)
        
        

        body_list = []
        for sub_node in node.body:
            sub_node.ext_class_name = class_name
            body_list.append(self.trans(sub_node))

        deco_list = []
        for decorator in node.decorator_list:
            try:
                if decorator.__class__.__name__ == "Call" and self.trans(decorator.func) in ["build", "create_module"]:########################################
                    pass
                else:
                    deco_list.append(self.trans(decorator))
            except:
                print(body_list)
                print(deco_list)
                raise "deco trans error!"
        class_comment = ""
        for deco in deco_list:
            if deco.startswith("__comment"):
                class_comment = deco.split("(", 1)[1].rsplit(")", 1)[0]
                class_comment = Node_trans_cfg.class_comment(class_comment)

        

        body_list = "\n".join(body_list)
        body_list = body_list.strip()
        
        r = """
{base_list}
{class_comment}
{body_list}
""".format(**locals())
        return r
    def _str(self, s): return s
    def _Assign(self, node):
        #Assign(expr* targets, expr value, string? type_comment)
        class_name = node.ext_class_name
        target_list = [self.trans(target) for target in node.targets]
        if len(target_list) > 1:
            raise Exception("_Assign: Multi  left value!!")
        left = target_list[0]
        right = self.trans(node.value)[1:-1]
        r = ""
        if "self." in left:
            member_name = left.split(".")[1].strip()
            Type = right
            self.add_member(class_name, member_name, Type)
            r = Node_trans_cfg.type_and_name(Type, member_name)#"{Type} {member_name}".format(**locals())
        else:
            if left in ["mysql"]:
                return ""
            if left in ["rely"]:
                return r
            if left in ["std"]:
                headers = list(filter(None, right.split(" ") ))
                for header in headers:
                    r += "#include <{header}.h>\n".format(**locals())
                return r # free from  raise E. this is good if r == ""
            if left in ["macro"]:
                r += "#define {right}".format(**locals())
        if r == "":
            OOvar_on(__name__, target_list, "target_list")
            OOvar_on(__name__, left, right)
            raise Exception("_Assign r not set ")
        return r

    def _Name(self, node): 
        #Name(identifier id, expr_context ctx)
        return self.trans(node.id)
    def _Str(self, Str):  
        s = Str.s
        type_space = self
        return Node_trans_cfg._Str_proc(s, type_space)

    def _FunctionDef(self, node):
        # FunctionDef(identifier name, arguments args,
        #     stmt* body, expr* decorator_list, expr? returns,
        #     string? type_comment)
        func_name = node.name
        args = self.trans(node.args)
        returns = self.trans(node.returns)
        class_name = node.ext_class_name
        type_space = self
        
        
        deco_list = []
        for decorator in node.decorator_list:
            deco_list.append(self.trans(decorator))


        for arg in node.args.args:
            arg.ext_class_name = class_name
        if func_name == "__init__":
            for line in node.body:
                line.ext_class_name = class_name
            member_list = [self.trans(line) for line in node.body]
            member_list = self.add_tab(";\n".join(member_list))
            pack_set, pack_recover = "", ""
            for deco in deco_list:
                if deco.startswith("__pack"):
                    n = deco.split("(")[1].split(")")[0].strip()
                    pack_set = "#pragma pack ({n})".format(**locals())
                    pack_recover = "#pragma pack ()"
                    break
            r = """
{pack_set}
typedef struct {class_name}_obj__ {class_name}_obj;
struct {class_name}_obj__
{{
{member_list};
}};
{pack_recover}

""".format(**locals())
            return r.lstrip()
        else:
            func_line = Node_trans_cfg._FunctionDef_proc(class_name, func_name, returns, args, deco_list, type_space)
            func_line = func_line.strip()
            func_comment = ""
            
            for deco in deco_list:
                if deco.startswith("__comment"):
                    func_comment = deco.split("(", 1)[1].rsplit(")", 1)[0]
                    func_comment = Node_trans_cfg.func_comment(func_comment)
            r = """
{func_comment}
{func_line};
""".format(**locals())
            return r
    def _arguments(self, node):
        # arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs,
        #      expr* kw_defaults, arg? kwarg, expr* defaults)
        args = []
        for arg_node in node.args:
            arg = self.trans(arg_node)
            if "(" in arg:
                func_name, func_type = self.trans(arg_node.arg), self.trans(arg_node.annotation)
                arg = Node_trans_cfg._arguments_proc(func_name, func_type, self)
            args.append(arg)
        return ", ".join(args)
    def _arg(self, node):
        # arg = (identifier arg, expr? annotation, string? type_comment)
        #    attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
        
        arg = self.trans(node.arg)
        annotation = self.trans(node.annotation)
        Type, name = annotation, arg
        return Node_trans_cfg.type_and_name(Type, name)
    def _NoneType(self, node): Node_trans_cfg._NoneType_proc()
    def _Call(self, node): 
        #Call(expr func, expr* args, keyword* keywords)
        args = []
        for arg_node in node.args:   
            args.append(self.trans(arg_node))
        func = self.trans(node.func)
        type_space = self
        r = Node_trans_cfg._Call_proc(func, args, type_space)
        return r
    def _Attribute(self, node):
        #Attribute(expr value, identifier attr, expr_context ctx)
        attr = self.trans(node.attr)
        value = self.trans(node.value)
        r = "{value}.{attr}".format(**locals())
        return r
    def _BinOp(self, node):
        #BinOp(expr left, operator op, expr right)
        r = None
        op = self.trans(node.op)
        left = self.trans(node.left)
        right = self.trans(node.right)
        return "{left} {op} {right}".format(op=op, left=left, right=right)
    def _Mult(self, node): return "*"
    def _Pass(self, node): return Node_trans_cfg._Pass_proc()
    def _Num(self, node):
        return str(node.n)
    def _Expr(self, node):
        value = self.trans(node.value)
        return value


    # 用于模板类
    def _Subscript(self, node): pass
        #Subscript(expr value, slice slice, expr_context ctx)
    def _Index(self, node): pass
        #Index(expr value)
        
    def _Load(self, node): pass